/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * @file rw_api.c
 * @brief RW API函数实现
 */

#include "nci_feature.h"
#if IS_FEATURE_ON(NCI_FEATURE_RW)

#include "nfa_rw.h"
#include "rw_int.h"
#include "nfc_log_api.h"
#include "discover_int.h"
#include "nci_data.h"
#include "nfa_utils.h"
#include "rw_utils.h"
#include "nfc_config_api.h"

#define MAX_SELECT_ACTIVATE_TIMEOUT 2000

#define GET_RW_LOCK() if (nfa_rw_request_lock() != NCI_STATUS_OK) { \
    return NCI_STATUS_EXT_GET_LOCK_FAILED; \
}
#define RELEASE_RW_LOCK() nfa_rw_release_lock()

static uint32_t s_tag_timeout_table[NCI_RW_TAG_TYPE_MAX];
static bool s_disable_retry = false; // DATA指令传输失败时是否禁用重试
/**
 * @brief 设置指定类型卡片的指令传输超时时间
 *
 * @param tag_type 要设置的卡片类型
 * @param timeout 超时时间，单位ms
 *
 * @return 成功返回NCI_STATUS_OK，失败返回其他错误码
 */
tNCI_STATUS nfa_rw_set_transceive_timeout(tNCI_RW_TAG_TYPE tag_type, uint32_t timeout) {
    if (timeout == 0) {
        NFCLOG_E("timeout is invalid, %d", timeout);
        return NCI_STATUS_INVALID_PARAM;
    }
    if (tag_type >= NCI_RW_TAG_TYPE_MAX) {
        NFCLOG_E("tag type is invalid, %d", tag_type);
        return NCI_STATUS_INVALID_PARAM;
    }
    s_tag_timeout_table[tag_type] = timeout;
    return NCI_STATUS_OK;
}
/**
 * @brief 重置所有指令传输超时时间
 */
void nfa_rw_reset_all_transceive_timeout(void) {
    s_tag_timeout_table[NCI_RW_TAG_TYPE_A] = 618;
    s_tag_timeout_table[NCI_RW_TAG_TYPE_B] = 1000;
    s_tag_timeout_table[NCI_RW_TAG_TYPE_ISO_DEP] = 1500;
    s_tag_timeout_table[NCI_RW_TAG_TYPE_F] = 255;
    s_tag_timeout_table[NCI_RW_TAG_TYPE_V] = 1000;
    s_tag_timeout_table[NCI_RW_TAG_TYPE_NDEF] = 1000;
    s_tag_timeout_table[NCI_RW_TAG_TYPE_NDEF_FORMATABLE] = 1000;
    s_tag_timeout_table[NCI_RW_TAG_TYPE_M1] = 618;
    s_tag_timeout_table[NCI_RW_TAG_TYPE_MUL] = 618;
    s_tag_timeout_table[NCI_RW_TAG_TYPE_KOVIO] = 1000;
}
/**
 * @brief 获取指定类型卡片的指令传输超时时间
 *
 * @param tag_type 要获取的卡片类型
 *
 * @return 返回超时时间，单位ms
 */
uint32_t nfa_rw_get_transceive_timeout(tNCI_RW_TAG_TYPE tag_type) {
    if (tag_type >= NCI_RW_TAG_TYPE_MAX) {
        NFCLOG_E("tag type is invalid, %d, return default value", tag_type);
        return 1000;
    }
    return s_tag_timeout_table[tag_type];
}

static void notify_tag_select(tNCI_RW_TAG *p_tag) {
    tNCI_RW_TAG_API *p_api = rw_utils_get_tag_api(p_tag);
    if (p_api && p_api->on_select) {
        p_api->on_select();
    }
}

static void notify_tag_deselect(tNCI_RW_TAG *p_tag) {
    tNCI_RW_TAG_API *p_api = rw_utils_get_tag_api(p_tag);
    if (p_api && p_api->on_deselect) {
        p_api->on_deselect(p_tag);
    }
}

tNCI_STATUS nfa_rw_connect(uint8_t index) {
    GET_RW_LOCK();
#if IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    rw_watch_dog_set_state_no_lock(true);
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    tNCI_RW_TAG *p_tag = nfa_rw_get_activated_tag();
    if (p_tag == NULL) {
        NFCLOG_E("currtent tag is NULL");
        ret = NCI_STATUS_EXT_TAG_LOST;
        goto unlock;
    }
    if (index > p_tag->tech_size) {
        NFCLOG_E("index is invalid, %d", index);
        ret = NCI_STATUS_EXT_FAILED;
        goto unlock;
    }
    if (p_tag->index == index) {
        NFCLOG_I("already connected to the target");
        ret = NCI_STATUS_OK;
        goto unlock;
    }
    tNCI_RF_PROTOCOL target_protocol = p_tag->protocols[index];
    if (target_protocol != NCI_RF_PROTOCOL_ISO_DEP && target_protocol != NCI_RF_PROTOCOL_M1) {
        NFCLOG_E("target protocol 0x%02X, do nothing for non ISO-DEP and non M1", target_protocol);
        ret = NCI_STATUS_OK;
        goto unlock;
    }

    tNCI_RF_DISCOVERY_ID target_disc_id = p_tag->disc_ids[index];
    tNCI_RF_INTERFACE target_interface = p_tag->interfaces[index];
    tNCI_RW_TAG_TYPE target_tag_type = p_tag->tag_types[index];

    NFCLOG_I("target_disc_id: 0x%02X, target_protocol: 0x%02X, target_interface: 0x%02X, target_tag_type=%d", target_disc_id, target_protocol, target_interface, target_tag_type);

    notify_tag_deselect(p_tag);
    ret = rf_re_select(target_disc_id, target_protocol, target_interface, MAX_SELECT_ACTIVATE_TIMEOUT);
    if (ret == NCI_STATUS_OK) {
        p_tag->index = index;
        NFCLOG_I("connected to the target successfully");
        notify_tag_select(p_tag);
    }
unlock:
#if IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    rw_watch_dog_set_state_no_lock(false);
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    RELEASE_RW_LOCK();

    NFCLOG_I("ret: %d", ret);
    return ret;
}

tNCI_STATUS nfa_rw_reconnect() {
    GET_RW_LOCK();
#if IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    rw_watch_dog_set_state_no_lock(true);
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;

    tNCI_RW_TAG *p_tag = nfa_rw_get_activated_tag();
    if (p_tag == NULL) {
        NFCLOG_E("currtent tag is NULL");
        ret = NCI_STATUS_EXT_TAG_LOST;
        goto unlock;
    }

    NFCLOG_I("curr_handle: %d", p_tag->index);
    tNCI_RF_DISCOVERY_ID curr_disc_id = p_tag->disc_ids[p_tag->index];
    tNCI_RF_PROTOCOL curr_protocol = p_tag->protocols[p_tag->index];
    tNCI_RF_INTERFACE target_interface = 0xFF;

    if (curr_protocol == NCI_RF_PROTOCOL_ISO_DEP) {
        target_interface = NCI_RF_INTERFACE_ISO_DEP;
    } else if (curr_protocol == NCI_RF_PROTOCOL_M1) {
        target_interface = NCI_RF_INTERFACE_TAG_CMD;
    } else if (curr_protocol == NCI_RF_PROTOCOL_T2T) {
        target_interface = NCI_RF_INTERFACE_FRAME;
    } else {
        NFCLOG_I("curr protocol(0x%02X) not support reconnect", curr_protocol);
        ret = NCI_STATUS_OK;
        goto unlock;
    }

    notify_tag_deselect(p_tag);
    ret = rf_re_select(curr_disc_id, curr_protocol, target_interface, MAX_SELECT_ACTIVATE_TIMEOUT);
    if (ret == NCI_STATUS_OK) {
        // 更新index到当前连接的handle
        for (uint8_t i = 0; i < p_tag->tech_size; i++) {
            if (p_tag->disc_ids[i] == curr_disc_id &&
                p_tag->protocols[i] == curr_protocol &&
                p_tag->interfaces[i] == target_interface) {
                p_tag->index = i;
                break;
            }
        }
        notify_tag_select(p_tag);
    }

unlock:
#if IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    rw_watch_dog_set_state_no_lock(false);
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    RELEASE_RW_LOCK();
    NFCLOG_I("ret: %d", ret);
    return ret;
}

tNCI_STATUS nfa_rw_disconnect() {
#if IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    nfa_rw_watch_dog_stop();
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    GET_RW_LOCK();
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    ret = rf_deactivate(false);
    RELEASE_RW_LOCK();
    NFCLOG_I("ret: %d", ret);
    return ret;
}

/**
 * @brief 向卡片发送命令并获取响应
 *
 * @param[in] cmd 命令buf
 * @param[out] rsp 响应buf
 *
 * @return 成功返回NCI_STATUS_OK，失败返回其他
 */
tNCI_STATUS rw_transmit(tNCI_BUF *cmd, tNCI_BUF *rsp) {
    tNCI_RW_TAG *p_tag = nfa_rw_get_activated_tag();
    if (p_tag == NULL) {
        NFCLOG_E("currtent tag is NULL");
        return NCI_STATUS_EXT_TAG_LOST;
    }
    tNCI_RW_TAG_API *p_api = rw_utils_get_tag_api(p_tag);
    uint32_t timeout = nfa_rw_get_transceive_timeout(p_tag->tag_types[p_tag->index]);
    uint8_t max_retry_count = s_disable_retry ? 0 : (p_api ? p_api->max_retry_count : NCI_RW_DEFAULT_MAX_RETRY_COUNT);
    uint8_t retry_count = 0;
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    do {
        ret = rf_transmit(cmd, rsp, timeout);
        if (ret != NCI_STATUS_EXT_TIMEOUT && ret != NCI_STATUS_RF_PROTOCOL_EXCEPTION) {
            // 如果不是超时或者RF协议异常，则直接不进行重试
            break;
        }
        NFCLOG_W("transmit failed, ret: %d, retry: %d/%d", ret, retry_count, max_retry_count);
    } while (retry_count++ < max_retry_count);

    if (ret != NCI_STATUS_OK) {
        bool need_disconnect = false;
        if (p_api && p_api->disconnect_when_transmit_fail && p_api->disconnect_when_transmit_fail(cmd, ret)) {
            // 卡片协议实现了disconnect_when_transmit_fail接口，并且返回true，则需要断开连接
            need_disconnect = true;
        } else if (ret == NCI_STATUS_RF_PROTOCOL_EXCEPTION) {
            // 卡片协议没有实现disconnect_when_transmit_fail接口，但是transmit返回了RF_PROTOCOL_EXCEPTION，也需要断开连接
            need_disconnect = true;
        }
        if (need_disconnect) {
            NFCLOG_I("transmit failed, disconnect tag");
            nfa_rw_disconnect();
        }
        return ret;
    }
    if (p_api && p_api->check_transceive_resp) {
        ret = p_api->check_transceive_resp(rsp->data, &rsp->len);
        if (ret != NCI_STATUS_OK) {
            NFCLOG_E("check_transceive_resp failed, ret: %d, reconenct tag", ret);
            nfa_rw_reconnect();
        }
    }
    return ret;
}

tNCI_STATUS nfa_rw_transceive(uint8_t *p_data, uint16_t data_len, tNCI_RSP *p_rsp) {
    if (!p_data || !p_rsp) {
        NFCLOG_E("p_data or p_rsp is NULL");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    if (data_len == 0) {
        NFCLOG_E("data len is 0");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    GET_RW_LOCK();
#if IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    rw_watch_dog_set_state_no_lock(true);
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;

    tNCI_BUF *cmd = NULL;
    tNCI_BUF *rsp = NULL;

    tNCI_RW_TAG *p_tag = nfa_rw_get_activated_tag();
    if (p_tag == NULL) {
        NFCLOG_E("currtent tag is NULL");
        ret = NCI_STATUS_EXT_TAG_LOST;
        goto unlock;
    }

    cmd = alloc_nci_buf_with_cap(0, data_len);
    rsp = alloc_nci_buf(0);
    if (!cmd || !rsp) {
        NFCLOG_E("alloc nci buf failed");
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto unlock;
    }

    ARRAY_TO_BUF(cmd, p_data, data_len);
    s_disable_retry = true; // transceive期间禁用DATA指令重试
    ret = rw_transmit(cmd, rsp);
    s_disable_retry = false;
    if (ret != NCI_STATUS_OK) {
        if (ret == NCI_STATUS_EXT_TIMEOUT) {
            // 当tag在超时时间内没有响应，则认为tag丢失，返回错误码为tag丢失
            NFCLOG_E("wait tag response timeout");
            ret = NCI_STATUS_EXT_TAG_LOST;
        } else {
            NFCLOG_E("rw_transmit failed");
        }
        goto unlock;
    }

    // 将rsp中的数据交换到p_rsp中
    p_rsp->len = rsp->len;
    p_rsp->data = rsp->data;
    rsp->data = NULL;

unlock:
#if IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    rw_watch_dog_set_state_no_lock(false);
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    free_nci_buf(rsp);
    free_nci_buf(cmd);
    RELEASE_RW_LOCK();
    return ret;
}

tNCI_STATUS rw_presence_check_no_lock() {
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;

    tNCI_RW_TAG *p_tag = nfa_rw_get_activated_tag();
    if (!p_tag) {
        NFCLOG_E("currtent tag is NULL");
        return NCI_STATUS_EXT_TAG_LOST;
    }

    tNCI_RW_TAG_API *p_api = rw_utils_get_tag_api(p_tag);
    if (!p_api || !p_api->presence_check) {
        // 对于没有实现presence_check的tag，采用reselect的方式检测是否在场
        ret = rf_re_select(p_tag->disc_ids[p_tag->index], p_tag->protocols[p_tag->index], p_tag->interfaces[p_tag->index], MAX_SELECT_ACTIVATE_TIMEOUT);
    } else {
        // presence check期间禁用DATA指令重试
        s_disable_retry = true;
        ret = p_api->presence_check();
        s_disable_retry = false;
    }

    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("presence check failed");
    }
    return ret;
}

tNCI_STATUS nfa_rw_presence_check() {
    GET_RW_LOCK();
#if IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    rw_watch_dog_set_state_no_lock(true);
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    tNCI_STATUS ret = rw_presence_check_no_lock();
#if IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    rw_watch_dog_set_state_no_lock(false);
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    RELEASE_RW_LOCK();
    return ret;
}

tNCI_STATUS nfa_rw_ndef_detect(tNCI_RW_NDEF_INFO *p_ndef_info) {
    if (p_ndef_info == NULL) {
        NFCLOG_E("p_ndef_info is NULL");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    GET_RW_LOCK();
#if IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    rw_watch_dog_set_state_no_lock(true);
#endif
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;

    tNCI_RW_TAG *p_tag = nfa_rw_get_activated_tag();
    if (!p_tag) {
        NFCLOG_E("currtent tag is NULL");
        ret = NCI_STATUS_EXT_TAG_LOST;
        goto unlock;
    }
    tNCI_RW_TAG_API *p_api = rw_utils_get_tag_api(p_tag);
    if (!p_api || !p_api->ndef_detect) {
        ret = NCI_STATUS_EXT_NOT_SUPPORTED;
        goto unlock;
    }
    ret = p_api->ndef_detect(p_ndef_info);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("ndef detect failed");
    }

unlock:
#if IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    rw_watch_dog_set_state_no_lock(false);
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    RELEASE_RW_LOCK();
    return ret;
}

tNCI_STATUS nfa_rw_ndef_read(tNCI_RSP *p_rsp) {
    if (p_rsp == NULL) {
        NFCLOG_E("p_rsp is NULL");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    GET_RW_LOCK();
#if IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    rw_watch_dog_set_state_no_lock(true);
#endif
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    tNCI_RW_TAG *p_tag = nfa_rw_get_activated_tag();
    if (!p_tag) {
        NFCLOG_E("currtent tag is NULL");
        ret = NCI_STATUS_EXT_TAG_LOST;
        goto unlock;
    }
    tNCI_RW_TAG_API *p_api = rw_utils_get_tag_api(p_tag);
    if (!p_api || !p_api->ndef_read) {
        ret = NCI_STATUS_EXT_NOT_SUPPORTED;
        goto unlock;
    }
    ret = p_api->ndef_read(p_rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("ndef read failed");
    }
unlock:
#if IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    rw_watch_dog_set_state_no_lock(false);
#endif
    RELEASE_RW_LOCK();
    return ret;
}

tNCI_STATUS nfa_rw_ndef_format(uint8_t *p_key, uint8_t key_len) {
    (void) p_key;
    (void) key_len;
    GET_RW_LOCK();
#if IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    rw_watch_dog_set_state_no_lock(true);
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    tNCI_RW_TAG *p_tag = nfa_rw_get_activated_tag();
    if (!p_tag) {
        NFCLOG_E("currtent tag is NULL");
        ret = NCI_STATUS_EXT_TAG_LOST;
        goto unlock;
    }
    tNCI_RW_TAG_API *p_api = rw_utils_get_tag_api(p_tag);
    if (!p_api || !p_api->ndef_format) {
        ret = NCI_STATUS_EXT_NOT_SUPPORTED;
        goto unlock;
    }
    ret = p_api->ndef_format();
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("ndef format failed");
    }
unlock:
#if IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    rw_watch_dog_set_state_no_lock(false);
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    RELEASE_RW_LOCK();
    return ret;
}

tNCI_STATUS nfa_rw_ndef_write(uint8_t *p_data, uint32_t data_len) {
    if (!p_data || data_len == 0) {
        NFCLOG_E("p_data is NULL or data len is 0");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    GET_RW_LOCK();
#if IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    rw_watch_dog_set_state_no_lock(true);
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    tNCI_RW_TAG *p_tag = nfa_rw_get_activated_tag();
    if (!p_tag) {
        NFCLOG_E("currtent tag is NULL");
        ret = NCI_STATUS_EXT_TAG_LOST;
        goto unlock;
    }
    tNCI_RW_TAG_API *p_api = rw_utils_get_tag_api(p_tag);
    if (!p_api || !p_api->ndef_write) {
        ret = NCI_STATUS_EXT_NOT_SUPPORTED;
        goto unlock;
    }
    ret = p_api->ndef_write(p_data, data_len);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("ndef write failed");
    }

unlock:
#if IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    rw_watch_dog_set_state_no_lock(false);
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    RELEASE_RW_LOCK();
    return ret;
}

tNCI_STATUS nfa_rw_set_tag_read_only(bool is_hard_lock) {
    GET_RW_LOCK();
#if IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    rw_watch_dog_set_state_no_lock(true);
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    tNCI_RW_TAG *p_tag = nfa_rw_get_activated_tag();
    if (!p_tag) {
        NFCLOG_E("currtent tag is NULL");
        ret = NCI_STATUS_EXT_TAG_LOST;
        goto unlock;
    }
    tNCI_RF_PROTOCOL protocol = p_tag->protocols[p_tag->index];
    switch (protocol) {
        case NCI_RF_PROTOCOL_T1T:
        case NCI_RF_PROTOCOL_T2T:
        case NCI_RF_PROTOCOL_T3T:
        case NCI_RF_PROTOCOL_ISO_DEP:
        case NCI_RF_PROTOCOL_T5T:
            break;
        default:
            NFCLOG_E("cannot set read only for protocol=0x%02X", protocol);
            ret = NCI_STATUS_EXT_REJECTED;
            goto unlock;
    }
    if (is_hard_lock && (protocol == NCI_RF_PROTOCOL_ISO_DEP)) {
        NFCLOG_E("cannot set hard lock for ISO-DEP");
        ret = NCI_STATUS_EXT_REJECTED;
        goto unlock;
    }
    if (!is_hard_lock && (protocol == NCI_RF_PROTOCOL_T5T)) {
        NFCLOG_E("cannot set soft lock for T5T");
        ret = NCI_STATUS_EXT_REJECTED;
        goto unlock;
    }
    tNCI_RW_TAG_API *p_api = rw_utils_get_tag_api(p_tag);
    if (!p_api || !p_api->set_tag_read_only) {
        ret = NCI_STATUS_EXT_NOT_SUPPORTED;
        goto unlock;
    }
    ret = p_api->set_tag_read_only(is_hard_lock);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("set tag read only failed");
    }
unlock:
#if IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    rw_watch_dog_set_state_no_lock(false);
#endif // IS_FEATURE_ON(NCI_FEATURE_RW_EXT)
    RELEASE_RW_LOCK();
    return ret;
}

tNCI_STATUS nfa_rw_is_ndef_formatable() {
    GET_RW_LOCK();
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;
    tNCI_RW_TAG *p_tag = nfa_rw_get_activated_tag();
    if (!p_tag) {
        NFCLOG_E("currtent tag is NULL");
        ret = NCI_STATUS_EXT_TAG_LOST;
        goto unlock;
    }
    tNCI_RW_TAG_API *p_api = rw_utils_get_tag_api(p_tag);
    if (!p_api || !p_api->is_ndef_formatable) {
        ret = NCI_STATUS_EXT_NOT_SUPPORTED;
        goto unlock;
    }
    ret = p_api->is_ndef_formatable();
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("is ndef formatable failed, ret=%d", ret);
    }
unlock:
    RELEASE_RW_LOCK();
    return ret;
}

tNCI_RW_NDEF_TYPE nfa_rw_ndef_get_type(tNCI_RF_PROTOCOL protocol, tNCI_RW_TAG_TYPE tag_type) {
    tNCI_RW_NDEF_TYPE ndef_type = NCI_RW_NDEF_TYPE_UNKNOWN;
    switch (protocol)
    {
    case NCI_RF_PROTOCOL_T1T:
        ndef_type = NCI_RW_NDEF_TYPE1_TAG;
        break;
    case NCI_RF_PROTOCOL_T2T:
        ndef_type = NCI_RW_NDEF_TYPE2_TAG;
        break;
    case NCI_RF_PROTOCOL_T3T:
        ndef_type = NCI_RW_NDEF_TYPE3_TAG;
        break;
    case NCI_RF_PROTOCOL_ISO_DEP:
        ndef_type = NCI_RW_NDEF_TYPE4_TAG;
        break;
    case NCI_RF_PROTOCOL_M1:
        ndef_type = NCI_RW_NDEF_TYPE_M1_TAG;
        break;
    case NCI_RF_PROTOCOL_T5T:
        ndef_type = NCI_RW_NDEF_TYPE5_TAG;
        break;
    default:
        NFCLOG_E("unknown libnfc-nci type: %d", protocol);
        break;
    }
    NFCLOG_I("protocol: %d tag_type=%d, ndef_type: %d", protocol, tag_type, ndef_type);
    return ndef_type;
}
/**
 * @brief 获取IsoDep协议最大传输长度
 *
 * @return IsoDep协议最大传输长度
 */
uint32_t nfa_rw_get_iso_dep_max_transceive_length() {
    /* TODO: 从配置文件中获取
    uint32_t length = nfc_config_get()->vendor_cf.max_iso_dep_transceive_length;
    NFCLOG_I("iso_dep_max_transceive_length = %d", length);
    return length;
     */
    return 0xFEFF;
}

bool nfa_rw_is_ultralight_c() {
    uint8_t read_cmd[] = {0x30, 0x02};
    tNCI_RSP rsp = {0};
    bool is_ultralight_c = false;
    tNCI_STATUS ret = nfa_rw_transceive(read_cmd, sizeof(read_cmd), &rsp);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("nfa_rw_transceive failed, ret=%d", ret);
        goto cleanup;
    }
    if (!rsp.data || rsp.len != 16) {
        goto cleanup;
    }
    if (rsp.data[2] == 0 && rsp.data[3] == 0 && rsp.data[4] == 0 &&
        rsp.data[5] == 0 && rsp.data[6] == 0 && rsp.data[7] == 0) {
        if (rsp.data[8] == 0x02 && rsp.data[9] == 0x00) {
            is_ultralight_c = true;
        }
    } else {
        if (rsp.data[4] == 0x01 && rsp.data[5] < 0x20) {
            if (rsp.data[6] > 0x06) {
                is_ultralight_c = true;
            }
        }
    }
cleanup:
    nfa_utils_free_rsp(&rsp, true);
    return is_ultralight_c;
}

#endif // IS_FEATURE_ON(NCI_FEATURE_RW)
